#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <dir.h>

  typedef unsigned long  LONG;
  typedef unsigned short WORD;
  typedef unsigned char  BYTE;

  #define readw( x ) (fgetc(x) + (fgetc(x) << 8))
  #define wput( x, y ) fputc( (x), y ); fputc( (x) >> 8, y )

  FILE *df,
       *rf,
			 *sf,
			 *tf;

  char dfile[520];
  char rfile[520];
  char tfile[520];
  char dirc[520];

  struct _REGZ
  {
    WORD x,
         y,
         a;
  } reg;

  WORD attr,
	     x,
			 y,
			 x1,
			 y1;

  struct _MENU
	{ //
    char tag[32];
    WORD  loop;
    LONG offset,
         start,
 	       posi,
				 loca;
    WORD  count;
    BYTE data;
  } menu;


  BYTE ram[0xFFFF];

  LONG offsets[0x80],
       loop,
       tofs,
	     pos,
       noComp;


  LONG Snes2Pc( long ofs );

//---------------------------------//
//                                 //
//---------------------------------//
int  main ( int argc, char *argv[ ] )
{
  int  c;

  memset( ram, 0, 0xFFFF);
  memset( offsets, 0, 128 << 2);

  if ( argc < 2 ){
    printf("Usage: %s ROMFile", argv[0] );
    return -1;
  }

  strcpy( rfile, argv[1]);
  strcpy( dirc, argv[1] );
  //
  for ( c = strlen(dirc)-1; c > 0; c-- )
    if ( dirc[c] == '/' || dirc[c] == '\\' ) break;
  strcpy( &dirc[c], "/Menu" );
  mkdir( dirc );
  //

  sprintf( tfile, "%s/Menu2.txt", dirc );
  //
  rf = fopen( rfile, "rb" );
  tf = fopen( tfile, "wt" );
  //
  if ( !rf || !tf ){
    printf("Error: Could not open file(s)." );
    return -1;
  }
  //
  fprintf( tf,"// TAG ROMFILE  DATFILE  POINTER COLUMN  ROW  WIDTH  HEIGHT START_OFFSET  END_OFFSET STORAGE_TYPE\n" );

  //
  menu.offset = 0x858000;
//  menu.offset = 0x89806F;
  fseek( rf, Snes2Pc( menu.offset ), SEEK_SET );
  reg.x = readw( rf );
  reg.x &= 0x0FFF;
  reg.x >>= 1;
//  reg.x = 1;
  reg.y = -1;
  pos   = 0;
  //


  while( ++reg.y < reg.x )
	{
    fseek( rf, Snes2Pc( menu.offset + (reg.y << 1) ), SEEK_SET );
    reg.a = readw( rf );
    // Get to the data
    fseek( rf, tofs = Snes2Pc( (menu.offset & 0xFF0000) + reg.a), SEEK_SET );
//    fseek( rf, tofs = Snes2Pc(0x950000 + reg.a), SEEK_SET );

    //
    for ( loop = 0; loop < pos; loop++ ){
      if ( offsets[loop] == tofs ) goto _NextUp;
    }
    //
    offsets[ pos++ ] = tofs;

    //
    sprintf( dfile, "%s/LF_%02d.MNU", dirc, reg.y );
    //
    df = fopen( dfile, "wb" );
    if ( !df ){
      printf("Error opening output file" );
      return -1;
    }

    x1 = fgetc( rf ); // Column
    y1 = fgetc( rf ); // Row
    x = fgetc( rf ); // Width
    y = fgetc( rf ); // Height
    //
    menu.start = ftell( rf );

    // Save MenuEditor Header data
    fputc( y, df ); // Y size
    fputc( x, df ); // X size

    //
    menu.count = (x * y);
    attr       = 0x2200;
    noComp     = 0;
    //
    while( menu.count > 0 )
    { //
      menu.data = fgetc( rf );
      menu.loca = ftell( rf );
      // Process Data
      switch( menu.data )
      {
			  // 16-BIT Offset , Same BANK
        case 0xF0 : menu.loop = fgetc(rf);
                    menu.count -= menu.loop;
				            fread( &ram[0x09], 1, 2, rf );
                    menu.posi = ftell( rf );
                    //
                    fseek( rf, Snes2Pc( 0x850000 + (*(WORD *)&ram[0x09]) ), SEEK_SET );
                    //
//                    if ( !noComp ) noComp = (ftell( df ) >> 1) + 1;
                    //
                    while( menu.loop-- ){
                      menu.data = fgetc(rf);
                      wput( menu.data | attr, df );
                    }
                    //
                    fseek( rf, menu.posi, SEEK_SET );
                    break;

        // RLE
        case 0xF1 : menu.loop = fgetc(rf);
				            menu.data = fgetc(rf);
                    menu.count -= menu.loop;
                    //
                    if ( !noComp ) noComp = (ftell( df ) >> 1) + 1;
                    //
                    while( menu.loop-- ){ wput( menu.data | attr, df ); }
                    break;
        // 24-BIT Offset
        case 0xF2 : menu.loop = fgetc(rf);
				            fread( &ram[0x09], 1, 3, rf );
                    menu.posi = ftell( rf );
                    menu.count -= menu.loop;
                    //
                    fseek( rf, Snes2Pc( (*(long *)&ram[0x40]) ), SEEK_SET );
                    //
//                    if ( !noComp ) noComp = (ftell( df ) >> 1) + 1;
                    //
                    while( menu.loop-- ){
                      menu.data = fgetc(rf);
                      wput( menu.data | attr, df );
				            }
                    //
                    fseek( rf, menu.posi, SEEK_SET );
                    break;

        // RLE with value in $12C2 [ $00 ??]
        case 0xF3 : menu.loop = fgetc(rf);
				            menu.data = ram[0x12C2];
                    menu.count -= menu.loop;
                    //
//                    if ( !noComp ) noComp = (ftell( df ) >> 1) + 1;
                    //
                    while( menu.loop-- ){ wput( menu.data  | attr, df ); }
                    break;

        // DATA, Attribute ORA with $12BC
        case 0xF4 : menu.data = fgetc(rf);
				            *(WORD *)&ram[0] = ((WORD)fgetc(rf) << 8);
				            wput( menu.data | (attr | (*(WORD *)&ram[0])), df );
                    menu.count--;
                    break;

        // New Attribute BYTE
        case 0xF5 : *(WORD*)&ram[0x12D9] = attr;
				            attr = (WORD)fgetc(rf) << 8;
										break;

        // Restore Old Attribute BYTE
        case 0xF6 : attr = *(WORD*)&ram[0x12D9];
				            break;

        // DATA = Control Code Store
        case 0xF7 : menu.data = fgetc( rf );
                    wput( attr | menu.data, df );
                    menu.count--;
                    break;

        // BYTE = Count to store $01, Code added to ROM by Bongo`
        case 0xF8 : menu.loop = fgetc(rf);
				            menu.data = 0x01;
                    menu.count -= menu.loop;
                    //
                    while( menu.loop-- ) wput( menu.data | attr, df );
                    break;

        // Regular Data
        default   : wput( menu.data | attr, df );
                    menu.count--;
				            break;
      }
     }// WEND


//  fprintf( tf,"// TAG ROMFILE  DATFILE  POINTER COLUMN  ROW  WIDTH  HEIGHT START_OFFSET  END_OFFSET STORAGE_TYPE\n" );
     fprintf( tf,
		          ".MENU %s  %s  %08X  %2d  %2d  %2d  %2d  %08lX  %08lX  %X\n",
              rfile,
              dfile,
              Snes2Pc( menu.offset + (reg.y << 1) ),
              x1, y1,
              x , y ,
              menu.start,
              ftell( rf ),
              noComp - 1
            );
     //
     fclose(df);

     _NextUp:
  }

  fcloseall( );
  return 0;
}



//-----------------------------//
// Load the program data Bank  //
//-----------------------------//
LONG Snes2Pc( long ofs )
{
  LONG val;

  if ( !ofs ) return 0;

  val = (((ofs | 0x800000) - 0x800000) & 0xFF0000) >> 1;
  val+= ((ofs & 0xFFFF) - 0x8000);

  return val;
}// END OF SU


